Skip to content

Ported fixes: iEMG SFAP units and execution route, fibre CV units, Gfluctdv noise - #43

Merged
DRohlf merged 4 commits into
mainfrom
fix/fdi-ported-fixes
Nov 7, 2026
Merged

DRohlf merged 4 commits into
mainfrom
fix/fdi-ported-fixes

Conversation

@DRohlf

@DRohlf DRohlf commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator

Second of four stacked PRs that replace #41: #40 → this → #44 (tooling) → #45 (fibre model). Base is fix/semg-farina2004; retarget to main once #40 merges, since GitHub only closes issues on merges into the default branch.

Closes #31, closes #33, closes #34.

Fixes

  • Intramuscular EMG: SFAP units, IAP length, wave polarity, dz #31 iEMG SFAP units: conductivities 1000× too large, half-length IAP with 8× current, inverted wave towards the shorter half, missing dz. Single-fibre SFAP within 3 % of an independent SI line source. Breaking (iEMG amplitudes typically 20–50× larger at a fine wire).
  • The execution= route (runtime/density.py, runtime/iemg.py) still had the old kernel. Its numba kernel now mirrors bioelectric.get_current_density: an equivalence test to rtol 1e-10, a MUAP test of the default against the execution= route, and the iEMG cache namespace moves to v3.
  • Gfluctdv conductance noise was silent #33 Gfluctdv noise was silent (GLOBAL multipliers left at 0).
  • Muscle fibre conduction velocities and large fibre layouts #34 Muscle fibre CVs were all clipped to 2.0 m/s (diameter in µm on a line in mm); large circular fibre layouts were capped and filled only at the diagonals.

Tests. Full suite: 412 passed, 2 skipped; later commits on #40 change docs only.

Upgrade notes. iEMG amplitudes and fibre CVs change and Gfluctdv pools become noisy; see CHANGELOG.md (Unreleased).

Gfluctdv.mod multiplies both fluctuating conductances by GLOBAL multex/multin,
which default to 0, so AlphaMN.insert_Gfluctdv() added a silent mechanism.
Set both to 1 on insert. Ported from the fresh-trunk line (bef5cbe79,
2026-04-17), which never reached main.
… fibre layouts

Fibre CV used a slope of 5.5 (m/s)/mm with diameters in mm, giving ~1.1 m/s
before the 2 m/s clip, so every fibre had exactly 2.0 m/s. Use CV = 0.95 m/s
+ 0.05 m/s per um (Nandedkar & Stalberg 1983), shared with
SurfaceFiberDispersion through CV_INTERCEPT__M_S / CV_PER_DIAMETER__M_S_PER_MM.
Affects intramuscular EMG; surface EMG uses the mean CV.

voronoi_pi1e5.csv covers a square, so only ~313 k points form a full disc.
Larger fibre counts got a corner-only outer ring and, above 399 499, a silent
cap. Those counts now use a scrambled Halton sequence in the disc (seeded from
MyoGen's RNG) with a warning; smaller counts are unchanged.

Fresh-trunk fixed both differently (be9cdfe35, a82923b2b); see
docs/pr/2026-11-01-upstream-changes.md for why its numbers were not used.
…ation

Four errors in the intramuscular source and volume conductor nearly cancelled
at the default 0.01 mm spatial step:

- muscle conductivities defaulted to 63 / 330 "S/m" (1000x tissue values);
  now 0.063 / 0.33 S/m, converted to S/mm (bioelectric.py, fiber_simulation.py)
- the Rosenfalck IAP was evaluated at 2x the distance with the chain rule
  applied twice (half-length IAP, 8x current); now lambda = 1 mm, as in sEMG
- the wave towards the shorter fibre half was subtracted, inverting it; the
  two waves now add (a second derivative is unchanged by reflection)
- calc_sfaps summed over z without the spatial step, so amplitude scaled with
  1/dz; both CPU and GPU paths now multiply by dz

A single-fibre SFAP through MotorUnitSim.calc_sfaps now matches an independent
SI line source within 3 % at 0.1-1 mm, is mirror-symmetric about the
end-plate, independent of dz, and identical on GPU and CPU
(tests/test_iemg_sfap_units.py). Output documented in mV.
runtime/density.py is a numba port of bioelectric.get_current_density
and still had the pre-fix kernel: IAP at twice the distance with the
chain rule applied twice, the shorter-half wave subtracted, and
runtime/iemg.py summed the line source without dz. MUAPs from
execution=ExecutionPolicy() disagreed with the default route (peak ratio
~1/8, correlation ~0.09 on a single fibre).

Pin the kernel to the reference with an equivalence test, add a
default-route vs execution-route MUAP test, and bump
IEMG_CACHE_NAMESPACE to v3 so stale cached templates are recomputed.
CHANGELOG entries for the ported fixes and the SFAP units.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant